package org.mentalsmash.crossroads.ui.cli;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.mentalsmash.crossroads.CrossroadsManager;
import org.mentalsmash.crossroads.Crossword;
import org.mentalsmash.crossroads.SolvingException;
import org.mentalsmash.crossroads.parsing.ParsingException;

import jargs.gnu.CmdLineParser;

/**
 * Command Line Interface for Crossroads compiler
 * @author Andrea Reale
 *
 */
public class CrossroadsCLI {
	
	private final static Logger log = Logger.getLogger(CrossroadsCLI.class);
	
	private final static String HELP_LONG = "help";
	private final static char HELP_SHORT = 'h';
	private final static String THEORY_LONG = "theory";
	private final static String XHTML_LONG = "xhtml";
	private final static String SVG_LONG = "svg";
	private final static String NODEF_LONG = "no-defs";
	private final static char SOLVE_SHORT = 's';
	private final static String SOLVE_LONG = "solve";
	private final static char VERSION_SHORT = 'v';
	private final static String VERSION_LONG = "version";
	
	private static boolean _helpOpt;
	private static boolean _versionOpt;
	private static boolean _solveOpt;
	private static boolean _noDefsOpt;
	private static String _theoryOpt;
	private static String _xhtmlOpt;
	private static String _svgOpt;
	


	private static void printUsage() {
        System.err.println(
        		"Usage: crosswordc [OPTIONS] source.schema\n" +
        		"\tcrosswordc -"+ HELP_SHORT + " for help\n");
    }
	
	private static void printHelp() {
		System.out.println(
				"java org.mentalsmash.crossroads.ui.cli.CrossroadsCLI [OPTIONS] SCHEMA_SOURCE\n\n" +
				"Default: java org.mentalsmash.crossroads.ui.cli.CrossroadsCLI --svg out.svg SCHEMA_SOURCE\n\n" +
				"Options:\n" +
					"\t--" + HELP_LONG + ", -" + HELP_SHORT + "\t\tprint this message and exit\n" +
					"\t--" + VERSION_LONG + ", -" + VERSION_SHORT + "\t\tprint the version information and exit\n" +
					"\t--" + THEORY_LONG + "<file>\t\tgenerate prolog theory into given file\n" +
					"\t--" + XHTML_LONG + "<file>\t\tgenerate xhtml description into given file\n" +
					"\t--" + SVG_LONG + "<file>\t\tgenerate svg representation and save it to given file\n" +
					"\t--" + NODEF_LONG + "\t\tDo not parse definitions file. (Useful if you want to save a bunch of time)\n" +
					"\t--" + SOLVE_LONG + "\t\t\ttry to solve the given crossword before printing the output"
				);
	}
	
	
	private static String[] parseArgs(String[] args){
		CmdLineParser argsParser = new CmdLineParser();
		
		CmdLineParser.Option help = argsParser.addBooleanOption(HELP_SHORT, HELP_LONG);
		CmdLineParser.Option version = argsParser.addBooleanOption(VERSION_SHORT, VERSION_LONG);
		CmdLineParser.Option noDefs = argsParser.addBooleanOption(NODEF_LONG);
		CmdLineParser.Option solve = argsParser.addBooleanOption(SOLVE_SHORT, SOLVE_LONG);
		CmdLineParser.Option theory = argsParser.addStringOption(THEORY_LONG);
		CmdLineParser.Option xhtml = argsParser.addStringOption(XHTML_LONG);
		CmdLineParser.Option svg = argsParser.addStringOption(SVG_LONG);
		
		try{
			argsParser.parse(args);
		} catch ( CmdLineParser.OptionException e ) {
            System.err.println(e.getMessage());
            printUsage();
            System.exit(2);
        }
		
		_helpOpt = (Boolean) argsParser.getOptionValue(help, Boolean.FALSE);
		_versionOpt = (Boolean) argsParser.getOptionValue(version, Boolean.FALSE);
		_noDefsOpt = (Boolean) argsParser.getOptionValue(noDefs, Boolean.FALSE);
		_solveOpt = (Boolean) argsParser.getOptionValue(solve, Boolean.FALSE);
		
		_theoryOpt = (String) argsParser.getOptionValue(theory);
		_xhtmlOpt = (String) argsParser.getOptionValue(xhtml);
		_svgOpt = (String) argsParser.getOptionValue(svg);
		
		return argsParser.getRemainingArgs();
	}
	
	public static void main(String[] args){
		
		String[] otherArgs = parseArgs(args);
		
		if(_versionOpt){
			printVersionInfo();
			System.exit(0);
		}
		if(_helpOpt){
			printHelp();
			System.exit(0);
		}
		
		//there should be always an argument left
		if(otherArgs.length != 1){
			printUsage();
			System.exit(3);
		}
		String sourceFilename = otherArgs[0];
		CrossroadsManager cm = null;
		try {
			cm = new CrossroadsManager();
		} catch (ParsingException e) {
			System.err.println("Some problem occurred while instantiating the parsing engine: " + e.getMessage());
			System.exit(-1);
		}
		System.out.println("Parsing sourcefile...");
		Crossword parsed = null;
		
		try{
			if(_noDefsOpt){
				parsed = cm.parseSchemaOnly(sourceFilename);
			} else
				parsed = cm.parseBoth(sourceFilename);
		} catch (FileNotFoundException e){
			System.err.println(e.getMessage());
			System.exit(-1);
		} catch (ParsingException e){
			System.err.println("Parsing Error: \n\t" + e.getMessage());
			System.exit(-1);
		}
		
		if(_solveOpt) {
			System.out.println("Trying to solve the crossword (this make take a long time) ...");
			try {
				cm.solve(parsed);
				System.out.println("Solution found!");
			} catch (SolvingException e) {
				System.err.println("The solver engine was unable to find a solution for the given crossword.");
			}
		}
		
		if(_svgOpt==null && _xhtmlOpt==null && _theoryOpt==null){
			//setting default options
			_svgOpt = "out.svg";
		}
		
		if(_theoryOpt != null) {
			exportToPlTheory(cm, parsed);
		}
		
		if(_svgOpt != null){
			exportToSvg(cm, parsed);
		}
		
		if(_xhtmlOpt != null) {
			exportToXhtml(cm, parsed);
		}
		
		
		
	}

	private static void exportToXhtml(CrossroadsManager cm, Crossword parsed) {
		System.out.println("Exporting crossword to XHTML in " + _xhtmlOpt);
		FileOutputStream xhtml = null;
		try{
			xhtml = new FileOutputStream(_xhtmlOpt);
			cm.generateXhtmlDescription(parsed,!_noDefsOpt, xhtml);
			xhtml.close();
		} catch(FileNotFoundException e){
			System.err.println("Unable to write to file " + _xhtmlOpt);
		} catch (IOException e){
			log.warn("Unabel to close " + _xhtmlOpt);
		}
	}

	private static void exportToSvg(CrossroadsManager cm, Crossword parsed) {
		System.out.println("Exporting crossword to SVG in " + _svgOpt);
		FileOutputStream svg = null;
		try{
			svg = new FileOutputStream(_svgOpt);
			cm.generateSvgDescription(parsed, !_noDefsOpt, svg);
			svg.close();
		} catch(FileNotFoundException e){
			System.err.println("Unable to write to file " + _svgOpt);
		} catch (IOException e){
			log.warn("Unabel to close " + _svgOpt);
		}
	}

	private static void exportToPlTheory(CrossroadsManager cm, Crossword parsed) {
		System.out.println("Exporting crossword to Prolog theory in " + _theoryOpt);
		FileOutputStream pl = null;
		try{
			pl = new FileOutputStream(_theoryOpt);
			cm.printPrologTheory(parsed, pl);
			pl.close();
		} catch(FileNotFoundException e){
			System.err.println("Unable to write to file " + _theoryOpt);
		} catch (IOException e){
			log.warn("Unabel to close " + _theoryOpt);
		}
	}

	private static void printVersionInfo() {
		System.out.println(
				"ccc - Crossroads Crossword Compiler version 0.0.1\n" +
				"Copyright (C) 2009 Andrea Reale\n" +
				"Some rights reserved. You may want to take a look at license.txt\n\n"
		);
		
	}
}
